package edu.uoc.vmerinom.tfc.service;

import java.util.Date;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.Query;

import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.Transactional;
import org.jboss.seam.log.Log;

import edu.uoc.vmerinom.tfc.domain.Perfil;

/**
 * Clase de servicios con las operaciones de acceso a base de datos para el
 * módulo de perfiles.
 * 
 * @author Víctor Manuel Merino Martínez
 * 
 */
@Name("perfilesService")
@Scope(ScopeType.CONVERSATION)
public class PerfilesService {
	/**
	 * Gestor de entidades.
	 */
	@In(create = true)
	EntityManager entityManager;

	/**
	 * Log para la trazabilidad de errores.
	 */
	@Logger
	Log log;

	/**
	 * Devuelve un listado de perfiles no administrador que no tengan fecha de
	 * baja indicada.
	 * 
	 * @return Listado de perfiles activos
	 */
	@SuppressWarnings("unchecked")
	public List<Perfil> obtenerPerfilesActivos() {
		if (log.isDebugEnabled()) {
			log.debug("PerfilesService.obtenerPerfilesActivos()");
		}
		final String query = "from Perfil p where (p.baja is null or p.baja > :currentDate) and p.administrador = false order by p.nombre";
		log.info(query);
		return entityManager.createQuery(query).setParameter("currentDate", new Date()).getResultList();
	}

	/**
	 * Devuelve un listado con los perfiles activos ordenados por nombre, es
	 * decir, aquellos perfiles que no tengan fecha de baja indicada o bien que
	 * dicha fecha sea posterior a la fecha actual.
	 * 
	 * @return Listado de perfiles activos
	 */
	@SuppressWarnings("unchecked")
	public List<Perfil> obtenerPerfilesActivosAdmin() {
		if (log.isDebugEnabled()) {
			log.debug("PerfilesService.obtenerPerfilesActivosAdmin()");
		}
		final String query = "from Perfil p where p.baja is null or p.baja > :currentDate order by p.nombre";
		log.info(query);
		return entityManager.createQuery(query).setParameter("currentDate", new Date()).getResultList();
	}

	/**
	 * Devuelve un listado con todos los perfiles del sistema excepto los que
	 * son perfiles de administrador.
	 * 
	 * @return Listado de perfiles
	 */
	@SuppressWarnings("unchecked")
	public List<Perfil> obtenerPerfiles() {
		if (log.isDebugEnabled()) {
			log.debug("PerfilesService.obtenerPerfiles()");
		}
		final String query = "from Perfil p where p.administrador = false order by p.nombre";
		log.info(query);
		return entityManager.createQuery(query).getResultList();
	}

	/**
	 * Devuelve un listado con todos los perfiles del sistema.
	 * 
	 * @return Listado de perfiles
	 */
	@SuppressWarnings("unchecked")
	public List<Perfil> obtenerPerfilesAdmin() {
		if (log.isDebugEnabled()) {
			log.debug("PerfilesService.obtenerPerfilesAdmin()");
		}
		final String query = "from Perfil p order by p.nombre";
		log.info(query);
		return entityManager.createQuery(query).getResultList();
	}

	/**
	 * Devuelve el perfil cuyo nombre coincida con el que recibe por parámetros.
	 * Permite filtrar por el identificador: si el identificador recibido es
	 * distinto de <code>null</code>, se buscará el perfil cuyo nombre coincida
	 * con el que recibe por parámetros, pero que no tenga el mismo
	 * identificador recibido. Si el perfil no se encuentra, el método devolverá
	 * <code>null</code>.
	 * 
	 * @param nombre
	 *            Nombre del perfil
	 * @param id
	 *            Identificador del perfil
	 * @return Perfil con el nombre recibido por parámetros
	 */
	public Perfil obtenerPerfil(String nombre, Integer id) {
		if (log.isDebugEnabled()) {
			log.debug("PerfilesService.obtenerPerfil(nombre:" + nombre + ", id:" + id + ")");
		}
		final StringBuffer queryString = new StringBuffer("from Perfil p where upper(p.nombre) like upper(:nombre)");
		if (id != null) {
			queryString.append(" and p.id != :id");
		}
		log.info(queryString);
		Query query = entityManager.createQuery(queryString.toString()).setParameter("nombre", nombre);
		if (id != null) {
			query.setParameter("id", id);
		}
		Perfil perfil = null;
		try {
			perfil = (Perfil) query.getSingleResult();
		} catch (final NoResultException e) {
			perfil = null;
		}
		return perfil;
	}

	/**
	 * Actualiza el estado del perfil para poder visualizar los datos actuales
	 * de base de datos.
	 * 
	 * @param perfil
	 *            Perfil a actualizar
	 */
	public void actualizarEstadoPerfil(Perfil perfil) {
		if (log.isDebugEnabled()) {
			log.debug("PerfilesService.actualizarEstadoPerfil(perfil:" + perfil + ")");
		}
		if (perfil != null && perfil.getId() != null) {
			entityManager.refresh(perfil);
		}
	}

	/**
	 * Inserta o modifica los datos del perfil que recibe por parámetros.
	 * 
	 * @param perfil
	 *            Perfil a insertar/modificar
	 */
	@Transactional
	public void insertarModificarPerfil(Perfil perfil) {
		if (log.isDebugEnabled()) {
			log.debug("PerfilesService.insertarModificarPerfil(perfil:" + perfil + ")");
		}
		if (perfil != null) {
			final Date hoy = new Date(System.currentTimeMillis());
			if (perfil.getId() == null) {
				perfil.setCreado(hoy);
			}
			perfil.setModificado(hoy);
			entityManager.persist(perfil);
		}
		entityManager.flush();
	}

}
